
import { Subject, Observable } from 'rxjs';
import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
export type RxWebSocketOptions = {
  url: string, // 连接地址
  reConnectTime?:number // 连接失败重连间隔时间 单位毫秒
}
export class RxWebSocket {
  private url: string = '';
  public wsSubject: WebSocketSubject<any>| null = null;
  public wsOpenSubject: Subject<any>| null = null;
  private reconnectTimer: NodeJS.Timeout| null = null;
  private reconnectTime: number = 2000; // 连接失败默认间隔2秒重连
  private heartBeatTimer: NodeJS.Timeout| null = null;
  private heartBeatTime: number = 300000;

  constructor(opt: RxWebSocketOptions) {
    this.url = opt.url;
    this.reconnectTime = opt.reConnectTime || this.reconnectTime;
    this.createSocket();
  }

  // 创建连接
  public createSocket() {
    this.wsOpenSubject = new Subject();
    this.wsSubject = webSocket({
      url: this.url,
      openObserver: this.wsOpenSubject,
    })
    this.wsSubject.subscribe()
    this.startHeartBeat();
    // 监听连接失败重连
    this.reConnect()
  }

  // 发送消息
  public sendMessage(value: string) {
    this.wsSubject?.next(value)
  }

  // 关闭连接
  public closeWebSocket() {
    this.wsSubject?.complete();
    if (this.heartBeatTimer) {
      clearInterval(this.heartBeatTimer)
      this.heartBeatTimer = null
    }
  }
  // 发送心跳包给后端
  private startHeartBeat() {
    this.wsOpenSubject?.subscribe(() => {
      this.heartBeatTimer = setInterval(() => {
        this.wsSubject?.next('ping')
      }, this.heartBeatTime)
    })
  }
  // 重连
  private reConnect() {
    this.wsSubject?.subscribe({
      error: err => {
        if(this.reconnectTimer) {
          clearInterval(this.reconnectTimer)
          this.reconnectTimer = null
        }
        this.reconnectTimer = setInterval(() => {
          this.createSocket();
        }, this.reconnectTime);
        
        console.log('连接失败', err)
      }
    });
  }
  
}

// 使用命名空间创建单列模式调用
export namespace RxWebSocketSingleton {
  let instance: RxWebSocket;
  export function getInstance(opt: RxWebSocketOptions): RxWebSocket {
      if (!instance) {
          instance = new RxWebSocket(opt);
      }
      return instance;
  }
}